from weebotlib import *

##class WeewarUnit(object):
##  ''' Eventually we'd want an object to represent each unit. '''    
##  def __init__(self, x, y, unittype, quantity=10, finished=False):
##    self.x = int(x)
##    self.y = int(y)
##    self.unittype = unittype
##    self.quantity = int(quantity)
##    self.finished = finished
##    if self.finished=="false":
##      self.finished = False
##    if self.finished = "true":
##      self.finished = True

class WeewarMapCell(object):
  ''' Contains the data about each cell in the map for lookup.
  '''
  def __init__(self, x, y, terraintype, owner=None, unitinfo=None, finished=True):
    self.x = int(x)
    self.y = int(y)
    self.terraintype = terraintype
    self.owner = owner
    self.finished = finished
    self.unitinfo = unitinfo

class WeewarMapState(object):
  ''' Stores the state of everything we learn about the map. '''
  def __init__(self, mapid, gameinfo=None):
    self.id = mapid
    self.mapinfo = WeewarApiLib().getMapLayout(mapid)
    self.width = int(self.mapinfo.width.PCDATA)
    self.height = int(self.mapinfo.height.PCDATA)
    self.board = [None]*(1+self.width)
    # this is used primarily for telling whether we should be hovercrafty or
    #   troopery
    self.terraincount = {"total":0,"Water":0,"Swamp":0,"Forest":0,"Mountain":0,"Desert":0}
    for j in xrange(len(self.board)):
      self.board[j] = [None]*(1+self.height)
    for cell in self.mapinfo.terrains.terrain:
      thiscell = WeewarMapCell(cell.x, cell.y, cell.type)
      self.board[int(cell.x)][int(cell.y)] = thiscell
      if cell.type in self.terraincount:
        self.terraincount[str(cell.type)]=self.terraincount[str(cell.type)]+1
      else:
        self.terraincount[str(cell.type)]=1
      self.terraincount["total"]=self.terraincount["total"]+1
    if gameinfo:
      for faction in gameinfo.factions.faction:
        try:
          # get all player bases/ports/airfields
          for terrain in faction.terrain:
            cell = self.board[int(terrain.x)][int(terrain.y)]
            cell.owner=faction.playerName
            cell.finished=(terrain.finished=='true')
        except AttributeError:
          # the map doesn't have a cell here
          pass
        try:
          for unit in faction.unit:
            # get all units on the map
            cell = self.board[int(unit.x)][int(unit.y)]
            cell.unitinfo = unit
            cell.unitinfo.owner = faction.playerName
        except AttributeError:
          # the map doesn't have a cell here
          pass
  def get(self, x, y):
    ''' Returns the WeewarMapCell for that position'''
    return self.board[int(x)][int(y)]
          
class WeewarGame(object):
  ''' Gathers and provides information about the current Weewar game
  '''
  def __init__(self, gameinfo):
    self.info = gameinfo
    self.state = self.info.state.PCDATA
    self.round = int(self.info.round.PCDATA)
    self.gamename = self.info.name.PCDATA
    self.id = int(self.info.id.PCDATA)
    self.url = self.info.url.PCDATA
    self.rated = self.info.rated.PCDATA
    self.mapid = int(self.info.map.PCDATA)
    self.mapstate = WeewarMapState(self.mapid,gameinfo)
  def getCurrentPlayer(self):
    if self.state!="running":
      return None
    else:
      for player in self.info.players.player:
        if player.__dict__.has_key("current"):
          return player.PCDATA
      return None
  def getPlayerUnits(self, username):
    units = []
    for faction in self.info.factions.faction:
      if faction.playerName != username:
        continue
      if faction.__dict__.has_key("unit"):
        for unit in faction.unit:
          units.append(unit)
    return units
  def getPlayerTerritory(self, username):
    spaces = []
    for faction in self.info.factions.faction:
      if faction.playerName != username:
        continue
      if faction.__dict__.has_key("terrain"):
        for terrain in faction.terrain:
          spaces.append(terrain)
    return spaces

def distance(x,y,cx,cy):
  ''' Port of hexmap distance function from ZappBrannigan
  '''
  import math
  yh = y % 2
  x1 = int(float(x- math.ceil(abs(cy-y)-yh)/2))
  x2 = int(float(x+ math.floor(abs(cy-y)+yh)/2))
  if (x1 <= cx and x2 >= cx):
    return abs(cy-y)
  elif x1 > cx:
    return abs(cy-y) + abs(cx-x1)
  else:
    return abs(cy-y) + abs(cx-x2)

def findNearest(x, y, mapstate, testcell):
  ''' Searches the map for the nearest something that satisfies the callback
       function testcell(cell). Returns a tuple of (cell, distance)
  '''
  mindist = 9999
  mindistcell = None
  for mx in xrange(mapstate.width):
    for my in xrange(mapstate.height):
      cell = mapstate.get(mx, my)
      if testcell(cell):
        dist = distance(x,y,mx,my)
        if dist < mindist:
          mindist = dist
          mindistcell = cell
  return (mindistcell, mindist)
